/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/*
 * Toplogy Viewer
 */

package cgl.narada.topology.viewer;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * This class represents a node(broker node) in the system. It stores and 
 * operates on all the information required for a node.
 */
public class Node {
    public static int INVALID_VALUE = -1;

    public int nodeId;
    public int parentClusterId;
    public int parentSClusterId;
    public int parentSSClusterId;
    
    public List clients;
    public Position nodeLocation;

    /**
     * Empty Constructor.
     */
    public Node() {
	nodeLocation = new Position();
	clients = new ArrayList();
    }

    /**
     * Constructor, initializes the components constituting the node Address
     * @param nodeId id of a node.
     * @param pClusterId id of a cluster containg the node.
     * @param pSClusterId id of a super cluster containg the node.
     * @param pSSClusterId id of a super super cluster containg the node.
     */
    public Node(int nodeId, int pClusterId, int pSClusterId, int pSSClusterId) 
    {
	this.nodeId = nodeId;
	this.parentClusterId = pClusterId;
	this.parentSClusterId = pSClusterId;
	this.parentSSClusterId = pSSClusterId;
	nodeLocation = new Position();
	clients = new ArrayList();
    }
    
    /**
     * Depending upon the location of the node and screen limits, returns true
     * if whole or part of the node is visible on the screen otherwise returns
     * false.
     * @param  limitX1 lower limit for X-coordinate
     * @param  limitY1 lower limit for Y-coordinate
     * @param  limitX2 upper limit for X-coordinate
     * @param  limitY2 upper limit for Y-coordinate
     * @return true if whole or part of the node is visible on the screen 
     *         otherwise returns false. 
     */
    public boolean canFitOnPanel(int limitX1, int limitY1, int limitX2, 
				 int limitY2) {
	if (((nodeLocation.getCenterX() + nodeLocation.getRadius() < limitX1)
	     || (nodeLocation.getCenterX() - nodeLocation.getRadius() 
		 > limitX2))
	    || ((nodeLocation.getCenterY() + nodeLocation.getRadius() 
		 < limitY1)
		|| (nodeLocation.getCenterY() - nodeLocation.getRadius() 
		    > limitY2))) {
	    return false;
	} else {
	    return true;
	}
    }

    /**
     * Draws a filled circle representing this node on the screen. Color and
     * Position of the node is decided by the <code>nodeLocation</code> object.
     * @param  g <code>Graphics</code> object for image drawing.
     * @param  limitX1 lower limit for X-coordinate
     * @param  limitY1 lower limit for Y-coordinate
     * @param  limitX2 upper limit for X-coordinate
     * @param  limitY2 upper limit for Y-coordinate
     */
    public void drawNode(Graphics g, int limitX1, int limitY1, int limitX2, 
			 int limitY2) {
	boolean isNodeOnPanel = canFitOnPanel(limitX1, limitY1, limitX2, 
					      limitY2);
	/* if any part of the node can fall on the visible panel then draw it 
	 * otherwise don't draw it at all
	 */
	if (isNodeOnPanel) {
	    /*
	      g.setColor(Color.white);
	      g.fillOval((int) (nodeLocation.getCenterX() 
			      - nodeLocation.getRadius()),
		       (int) (nodeLocation.getCenterY()
			      - nodeLocation.getRadius()),
		       (int) nodeLocation.getRadius() * 2,
		       (int) nodeLocation.getRadius() * 2);
	    */
	    g.setColor(nodeLocation.getColor());
	    g.fillOval((int) (nodeLocation.getCenterX() 
			      - nodeLocation.getRadius()),
		       (int) (nodeLocation.getCenterY()
			      - nodeLocation.getRadius()),
		       (int) nodeLocation.getRadius() * 2,
		       (int) nodeLocation.getRadius() * 2);
	    Font text = new Font("Arial", 2, 
				 (int) nodeLocation.getRadius() / 6);
	    g.setFont(text);
	    g.setColor(Color.BLACK);
	    g.drawString(String.valueOf(nodeId),
			 (int) nodeLocation.getCenterX(),
			 (int) (nodeLocation.getCenterY() - 
				nodeLocation.getRadius() * 0.8));
	}
    }

    /**
     * Gets a <code>Subscription</code> object corresponding to the specified 
     * client id.
     * @param  clientId id of a client
     * @return <code>Subscription</code> object associated with the client id.
     */
    public Subscription getClient(int clientId) {
	Iterator it = clients.iterator();
	while (it.hasNext()) {
	    Subscription s = (Subscription) it.next();
	    if (s.clientId == clientId) {
		return s;
	    }
	}
	return null;
    }

    /**
     * Gets all the <code>Subscription</code> objects associated with all the
     * clients for this node.
     * @return <code>List</code> of <code>Subscription</code> objects.
     */
    public List getAllClients() {
	Iterator it = clients.iterator();
	List clientList = new ArrayList();
	while (it.hasNext()) {
	    Subscription s = (Subscription) it.next();
	    clientList.add(s);
	}
	return clientList;
    }

    /**
     * Adds a client to the broker node.
     * @param clientId id of a client.
     * @param clientType type of a client.
     */
    public void addClient(int clientId, String clientType) {
	if (getClient(clientId) == null) {
	    clients.add(new Subscription(clientId, clientType));
	}
    }

    /**
     * Adds a topic requested by the specified client to the broker node.
     * @param clientId id of a client for which topic needs to be added.
     * @param topic <code>String</code> representation of the topic to be added
     */
    public void addTopic(int clientId, String topic)
	throws TopologyException {
	Subscription s = getClient(clientId);
	if (s == null) {
	    throw new TopologyException("client absent while adding topic");
	} else {
	    s.addTopic(topic);
	}
    }

    /**
     * Deletes the specified topic from the specified client associated with 
     * the broker node.
     * @param  clientId id of the client whose topic is being deleted.
     * @param  topic to be deleted.
     * @throws TopologyException if the specified client is not found with this
     *         broker node.
     */
    public void deleteTopic(int clientId, String topic) 
	throws TopologyException {
	Subscription s = getClient(clientId);
	if (s == null) {
	    throw new TopologyException("client absent while deleting a"
					+ "topic");
	} else {
	    s.deleteTopic(topic);
	}
    }

    /**
     * Deletes all the topics requested by a specified client.
     * @param  clientId id of a client whose topics are being deleted.
     * @throws TopologyException if the specified client is not found with this
     *         broker node.
     */ 
    public void deleteAllTopics(int clientId) 
	throws TopologyException {
	Subscription s = getClient(clientId);
	if (s == null) {
	    throw new TopologyException("client absent while deleting all"
					+ "topics");
	} else {
	    s.deleteAllTopics();
	}
    }

    /**
     * Deletes the specified client associated with the broker node.
     * @param  clientId id of a client being deleted.
     * @throws TopologyException if the specified client is not found.
     */
    public void deleteClient(int clientId) throws TopologyException {
	Subscription s = getClient(clientId);
	if (s == null) {
	    throw new TopologyException("client id absent while deletion");
	} else {
	    s.deleteAllTopics();
	    clients.remove(s);
	}
    }
    
    /**
     * Deletes all the clients associated with this broker node.
     */
    public void deleteAllClients() {
	Iterator it = clients.iterator();
	while(it.hasNext()) {
	    Subscription s = (Subscription) it.next();
	    s.deleteAllTopics();
	    it.remove();
	}
    }

    /**
     * Returns <code>String</code> representation of node address 
     * (eg. 1.2.3.4)
     * @return String representation of node address.
     */
    public String getNodeAddress() {
	return String.valueOf(parentSSClusterId) +  "." 
	    + String.valueOf(parentSClusterId) + "."
	    + String.valueOf(parentClusterId) + "."
	    + String.valueOf(nodeId);
    }
};
	    
